package com.hsj.springai.service;

import com.hsj.springai.service.sell.*;
import jakarta.annotation.Resource;
import org.aspectj.weaver.ast.Or;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SellService {
    @Resource
    private SellMapper sellMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private RedisUtils redisUtils;

    /**
     * 方案一：通过数据库update的时候带上kunCun>0的条件 相当于用数据库的行锁来实现高并发防止超卖
     * 缺点： 因为数据库连接有限、扛不住特别的并发、且一直占用连接资源会浪费数据库资源
     */
    @Transactional
    public String miaoSha(long productId, long userId) {
        //获取秒杀商品
        Product product = sellMapper.selectOne(productId);
        if (null != product && product.getKuCun() < 0) {
            return "库存售完";
        }
        //数据库层面防止超卖
        // update product set kuCun = kuCun -1 where id = 166 and kuCun > 0;   //因为在update的时候表会加行锁，带上条件 kunCun>0 就可以防止超卖问题
        int updateResult = sellMapper.updateProduct(productId);
        if (updateResult < 1) {
            return "抢购失败、请重试";
        }
        orderMapper.createOrder(new Order());
        return "下单成功";
    }

    /**
     * 方案二：通过使用 redis的并发性能，来支持高并发，并通过redis控制库存，因为redis单线程，天然锁
     */
    @Transactional
    public String miaoSha1(long productId, long userId) {
        //redis的唯一key，  对于热点商品可以对key做分片存储，轮询往redis集群的每个节点里面放    key
        String miaoShaKey = "miao:sha:" + productId;
        //获取redis里的库存信息
        int kuCun = redisUtils.getKuCun(miaoShaKey);
        if (kuCun < 1) {
            return "库存售完";
        }
        //redis原子减操作、
        int shengYuKuCun = redisUtils.decr(miaoShaKey, 1);
        if(shengYuKuCun < 0 ){
            //原子加操作
            redisUtils.incr(miaoShaKey);
            return "抢购失败";
        }
        //异步将库存写会数据库
        return "下单成功";
    }
}

    // 防止重复消费：      在发送MQ之前，先插入 消息发送表、 等消费者消费完执行完逻辑后，再将发送表的状态改成已处理
    // 消费的时候保证幂等： 用户的openId+活动Id  放入redis setNx
    // 防止消息丢失：      job重发、在消息发送表定时查看是否有 未执行成功的消息，如果有未成功的任务 就job重发， 这样消息就不丢失
    // MQ消息积压处理：    1）由于最后下单逻辑负责要插很多库，较慢，导致MQ消息积压，可以现将插入动作异步，先放缓存，再异步入库。 如果需要查订单可以先查库没有的话，再查缓存
    //                   2） 可以将MQ超时的订单丢弃、直接返回前端下单失败，让他重新下单（不建议）
    // redis挂了如何处理   如果redis挂了不要报错，而是将放入redis的对象 通过log 放库， 等redis重启后，再用job将库里的数据重放redis  ｜ 备用redis集群，将地址一改速度上线
    // redis主从切换导致超卖，

